package effects;

import java.util.ArrayList;
import java.util.List;

import loadsave.Memento;
import loadsave.loadsaveobject.Iterator;
import loadsave.loadsaveobject.LoadSaveCollectionComposite;
import loadsave.loadsaveobject.LoadSaveIndex;
import loadsave.loadsaveobject.LoadSaveObject;
import loadsave.loadsaveobject.LoadSaveObjectComposite;
import loadsave.loadsaveobject.LoadSavePrimitive;
import model.ModelObject;
import stat.StatList;
import stat.StatType;
import visitors.EffectsVisitable;
import visitors.EffectsVisitor;

/**
 * The Effect class is meant to provide the
 * visitable interface for enacting effect
 * functionalities on target and/or source
 * objects.  This class is required to unify
 * the Effect subtypes with a common interface
 * for Visitor interaction.
 * 
 * The Effect class's responsibility is to
 * interface the accept() method in order to
 * allow state changes to targets and/or sources
 * of the effect.
 * 
 * @author DangMH
 *
 */
public abstract class Effect extends ModelObject implements EffectsVisitable, Cloneable {
	protected List<StatType> relevantStats = new ArrayList<StatType>();
	protected List<StatType> outputStats = new ArrayList<StatType>();
	protected int mutator = 1;
	
	/**
	 * Empty constructor
	 */
	public Effect() {
		super("");
	}
	
	/**
	 * Parameterized constructor
	 * @param name
	 */
	public Effect(String name) {
		super(name);
	}
	
	protected void setMutator( int mutator ) {
		this.mutator = mutator;
	}
	
	public int getMutator() {
		return mutator;
	}
	
	/**
	 * Protected get method
	 */
	protected List<StatType> getRelevantStats() {
		return relevantStats;
	}
	
	/**
	 * Protected mutator method
	 */
	public void addRelevantStat( StatType ... statTypes ) {
		for( StatType st : statTypes ) {
			relevantStats.add( st );
		}
	}
	
	/**
	 * Protected get method
	 */
	protected List<StatType> getOutputStats() {
		return outputStats;
	}
	
	/**
	 * Protected mutator method
	 */
	public void addOutputStat( StatType ... statTypes ) {
		for( StatType st : statTypes ) {
			outputStats.add( st );
		}
	}
	
	public abstract void accept( EffectsVisitor ev );
	public abstract StatList computeStats();
	public abstract void setStats( StatList statList );
	
	@Override
	public Memento getMemento() {
		return new Memento() {

			@Override
			public LoadSaveObject getState() {
				LoadSaveObject lso = Effect.super.getMemento().getState();
				LoadSaveObjectComposite toReturn = new LoadSaveObjectComposite("", "Effect");
				Iterator<LoadSaveObject> i = lso.getIterator();
				for (i.init(); i.hasNext(); i.next()) {
					toReturn.add(i.getCurrKey().getValue(), i.getCurrVal());
				}
				LoadSaveCollectionComposite lscc = new LoadSaveCollectionComposite("relevantStats", "ArrayList", "StatType");
				int ind = 0;
				for (StatType s : relevantStats) {
					lscc.add(new LoadSaveIndex(ind++), new LoadSavePrimitive("", "", s.toString()));
				}
				LoadSaveCollectionComposite lscc2 = new LoadSaveCollectionComposite("outputStats", "ArrayList", "StatType");
				int ind2 = 0;
				for (StatType s : outputStats) {
					lscc2.add(new LoadSaveIndex(ind2++), new LoadSavePrimitive("", "", s.toString()));
				}
				toReturn.add(lscc2.getName(), lscc2);
				
				toReturn.add( "mutator", new LoadSavePrimitive( "mutator", "int", String.valueOf( mutator ) ) );
				
				return toReturn;
			}

			@Override
			public void restoreState(LoadSaveObject lso) {
				Effect.super.getMemento().restoreState(lso);
				Iterator<LoadSaveObject> i = lso.get("relevantStats").getIterator();
				relevantStats = new ArrayList<StatType>();
				for (i.init(); i.hasNext(); i.next()) {
					relevantStats.add(StatType.valueOf(i.getCurrVal().getValue()));
				}
				Iterator<LoadSaveObject> i2 = lso.get("outputStats").getIterator();
				outputStats = new ArrayList<StatType>();
				for (i2.init(); i2.hasNext(); i2.next()) {
					outputStats.add(StatType.valueOf(i2.getCurrVal().getValue()));
				}
				
				mutator = Integer.valueOf( lso.get( "mutator" ).getValue() );
			}
			
		};
	}
	
	public abstract Effect clone();
}
